package br.edu.fasete.javaroad.plugin.amateras;

import java.util.List;
import java.util.Map;

import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableColumn;

import net.java.amateras.uml.classdiagram.model.Argument;
import net.java.amateras.uml.classdiagram.model.AssociationModel;
import net.java.amateras.uml.classdiagram.model.AttributeModel;
import net.java.amateras.uml.classdiagram.model.ClassModel;
import net.java.amateras.uml.classdiagram.model.CommonEntityModel;
import net.java.amateras.uml.classdiagram.model.CompositeModel;
import net.java.amateras.uml.classdiagram.model.GeneralizationModel;
import net.java.amateras.uml.classdiagram.model.InterfaceModel;
import net.java.amateras.uml.classdiagram.model.OperationModel;
import net.java.amateras.uml.classdiagram.model.RealizationModel;
import net.java.amateras.uml.model.AbstractUMLEntityModel;

import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.awt.SWT_AWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Label;

import br.edu.fasete.javaroad.base.JavaRoad;
import br.edu.fasete.javaroad.base.Util;
import br.edu.fasete.javaroad.model.AttributeDescriptor;
import br.edu.fasete.javaroad.model.ClassAssociationDescriptor;
import br.edu.fasete.javaroad.model.ClassDescriptor;
import br.edu.fasete.javaroad.model.EntityDescriptor;
import br.edu.fasete.javaroad.model.FinderMethodDescriptor;
import br.edu.fasete.javaroad.model.InterfaceDescriptor;
import br.edu.fasete.javaroad.model.MethodDescriptor;
import br.edu.fasete.javaroad.model.ParameterDescriptor;
import br.edu.fasete.javaroad.model.architeture.Architeture;
import br.edu.fasete.javaroad.model.architeture.Component;
import br.edu.fasete.javaroad.plugin.ProjectConfigurations;
import br.edu.fasete.javaroad.plugin.gui.tablemodel.ComponentTableModel;
import br.edu.fasete.javaroad.plugin.gui.tablemodel.FileTableModel;

public class WizardPageComponents extends WizardPage {
	private IJavaProject project;
	private Map target;
	private Composite composite;
	private Map<String, Text> inputs;
	private ProjectConfigurations configurations;
	private JavaRoad javaOnRoad;

	private JTable listComponents;
	private JTable listFiles;
	private FileTableModel fileTableModel;
	private ComponentTableModel componentTableModel;
	
	private TableModelListener updateFileListEvent;
	
	public JavaRoad getJavaOnRoad() {
		if(javaOnRoad == null) {
			javaOnRoad = new JavaRoad(configurations);			
		}
		return javaOnRoad;
	}
	
	public FileTableModel getFileTableModel() {
		return fileTableModel;
	}
	
	public ComponentTableModel getComponentTableModel() {
		return componentTableModel;
	}
	
	public WizardPageComponents(IJavaProject project, Map target, ProjectConfigurations configurations) {
		super("Output Folder");
		setTitle("Select the components and files");
		this.target = target;
		this.project = project;
		this.configurations = configurations;
	}

	public void setVisible(boolean v) {
		if(v) {
			importModel();
			loadComponentList();
		}
		super.setVisible(v);
	}
	
	public void atualizarVariaveis() {
		for(String k: inputs.keySet()) {
			configurations.getArchiteture().getVariables().setValue(k, inputs.get(k).getText());
		}
	}
	
	public void createControl(Composite parent) {
		getShell().setText("Build");
		composite = new Composite(parent, SWT.NULL);
		composite.setLayout(new GridLayout(2, false));
		composite.setLayoutData(new GridData(GridData.FILL_BOTH));
		
		Label l1 = new Label(composite, SWT.PUSH);
		l1.setText("Select the components:");
		GridData gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan = 2;
		l1.setLayoutData(gd);
		
		
		Composite tableComp = new Composite(composite, SWT.EMBEDDED);
		gd = new GridData(GridData.FILL_BOTH);
		gd.horizontalSpan = 1;
		tableComp.setLayoutData(gd);
		java.awt.Frame fileTableFrame = SWT_AWT.new_Frame(tableComp);
		java.awt.Panel panel = new java.awt.Panel(new java.awt.BorderLayout());
		fileTableFrame.add(panel);
		JScrollPane painelListaComponentes = new JScrollPane();
		painelListaComponentes.setViewportView(getComponentList());
		panel.add(painelListaComponentes);
		
		
		Composite botoesComp = new Composite(composite, SWT.PUSH);
		RowLayout btLayout = new RowLayout();
		btLayout.pack = false;
		btLayout.type = SWT.VERTICAL;
		botoesComp.setLayout(btLayout);
		gd = new GridData(GridData.FILL_VERTICAL);
		botoesComp.setLayoutData(gd);
		
		Button B1 = new Button(botoesComp, SWT.PUSH);
		B1.setText("Select All");
		B1.addSelectionListener(new SelectionAdapter(){
			public void widgetSelected(SelectionEvent e){
				componentTableModel.removeTableModelListener(updateFileListEvent);
				componentTableModel.gerarTodos();
				componentTableModel.addTableModelListener(updateFileListEvent);
				loadFileList();
			}
		});		
		
		Button B2 = new Button(botoesComp, SWT.PUSH);
		B2.setText("Deselect All");
		B2.addSelectionListener(new SelectionAdapter(){
			public void widgetSelected(SelectionEvent e){
				componentTableModel.removeTableModelListener(updateFileListEvent);
				componentTableModel.gerarNenhum();
				componentTableModel.addTableModelListener(updateFileListEvent);
				loadFileList();
			}
		});		

		
		Label l2 = new Label(composite, SWT.PUSH);
		l2.setText("Select the files to be generated:");
		gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan = 2;
		l2.setLayoutData(gd);
		
		Composite filesComp = new Composite(composite, SWT.EMBEDDED);
		gd = new GridData(GridData.FILL_BOTH);
		gd.horizontalSpan = 1;
		filesComp.setLayoutData(gd);
		java.awt.Frame fileTableFrame2 = SWT_AWT.new_Frame(filesComp);
		java.awt.Panel panel2 = new java.awt.Panel(new java.awt.BorderLayout());
		fileTableFrame2.add(panel2);
		JScrollPane painelListaArquivos = new JScrollPane();
		painelListaArquivos.setViewportView(getFileList());
		panel2.add(painelListaArquivos);
		
		Composite botoesComp2 = new Composite(composite, SWT.PUSH);
		RowLayout btLayout2 = new RowLayout();
		btLayout2.pack = false;
		btLayout2.type = SWT.VERTICAL;
		botoesComp2.setLayout(btLayout2);
		gd = new GridData(GridData.FILL_VERTICAL);
		botoesComp2.setLayoutData(gd);		
		
		Button B3 = new Button(botoesComp2, SWT.PUSH);
		B3.setText("Select All");
		B3.addSelectionListener(new SelectionAdapter(){
			public void widgetSelected(SelectionEvent e){
				fileTableModel.selectAllFiles();
			}
		});		

		
		Button B4 = new Button(botoesComp2, SWT.PUSH);
		B4.setText("Select New");
		B4.addSelectionListener(new SelectionAdapter(){
			public void widgetSelected(SelectionEvent e){
				fileTableModel.selectInexistentFiles();
			}
		});		

		
		Button B5 = new Button(botoesComp2, SWT.PUSH);
		B5.setText("Deselect All");
		B5.addSelectionListener(new SelectionAdapter(){
			public void widgetSelected(SelectionEvent e){
				fileTableModel.selectNoFile();
			}
		});		

		setControl(composite);
	}
	
	public void importModel() {
		for(Object k: target.keySet()) {
			String cn = (String) k;
			Object obj = target.get(k);

			if (obj instanceof ClassModel) {
				ClassDescriptor jorclass = configurations.getListaClasses().findClass(cn);
				loadClass((ClassModel) obj, jorclass);
			} else {
				if(obj instanceof InterfaceModel) {
					InterfaceDescriptor jorInterface = configurations.getListaClasses().findInterface(cn);
					loadInterface((InterfaceModel) obj, jorInterface);
				}
			}
		}
	}
	
	public void loadClass(ClassModel model, ClassDescriptor jormodel) {
		jormodel.setAbstract(model.isAbstract());
		
		List conns = model.getModelSourceConnections();
		for(int i=0; i<conns.size(); i++){
			Object conn = conns.get(i);
			if(conn instanceof GeneralizationModel){
				jormodel.setSubclass(true);
				AbstractUMLEntityModel target = ((GeneralizationModel)conn).getTarget();
				if(target != null) {
					jormodel.setSuperClass(configurations.getListaClasses().findClass(getModelName(target)));
				}
			} else {
				if(conn instanceof RealizationModel) {
					AbstractUMLEntityModel target = ((RealizationModel)conn).getTarget();
					if(target != null) {
						jormodel.getInterfaces().add(configurations.getListaClasses().findInterface(getModelName(target)));
					} 
				} else {
					if(conn instanceof AssociationModel) {
						importAssociation((AssociationModel) conn, jormodel);
					}
				}
			}
		}
		
		importChildren(model, jormodel);
	} 
	
	public void importAssociation(AssociationModel ass, EntityDescriptor jormodel) {
		AbstractUMLEntityModel target = ass.getTarget();
		String st = ass.getStereoType();
		String name = Util.uncapitalize(getModelName(target));
		String type = "list";
		
		if(st != null &&  !st.trim().equals("")) {
			if(st.equalsIgnoreCase("list") || st.equalsIgnoreCase("set")) {
				type = st;
			} else
				name = st;
		} 						
		ClassAssociationDescriptor cad = new ClassAssociationDescriptor(name, getModelName(target), type);
		cad.setTargetClass(configurations.getListaClasses().findClass(getModelName(target)));
		if(ass instanceof CompositeModel) {
			cad.setCascade(true);
		}
		
		if(ass.getFromMultiplicity().trim().equals("1")) {
			if(ass.getToMultiplicity().trim().equals("1")) {
				jormodel.getAssociationsOneToOne().add(cad);
			} else {
				jormodel.getAssociationsOneToMany().add(cad);
			}
		} else {
			if(ass.getToMultiplicity().trim().equals("1")) {
				jormodel.getAssociationsManyToOne().add(cad);
			} else {
				jormodel.getAssociationsManyToMany().add(cad);
			}
		}
	}
	
	public void importChildren(CommonEntityModel model, EntityDescriptor jormodel) {
		List children = model.getChildren();
		for(int i=0;i<children.size();i++){
			Object child = children.get(i);
			if(child instanceof AttributeModel){
				AttributeModel attr = (AttributeModel) child;
				AttributeDescriptor attribute = new AttributeDescriptor();
				String visibility = attr.getVisibility().toString();
				if(!visibility.equals("package")){
					attribute.setVisibility(visibility);
				} else {
					attribute.setVisibility("");
				}
				attribute.setStatic(attr.isStatic());
				attribute.setName(attr.getName());
				attribute.setType(attr.getType());
				jormodel.getAttributeList().add(attribute);
				String find = attr.getSearchType().toString();
				if(!find.equalsIgnoreCase("none")) {
					FinderMethodDescriptor fd = new FinderMethodDescriptor(attribute);
					fd.setLista(find.equalsIgnoreCase("multiple"));
					jormodel.getDaoMethods().add(fd);
				}
			} else {
				if(child instanceof OperationModel) {
					OperationModel ope = (OperationModel) child;
					MethodDescriptor met = new MethodDescriptor();
					met.setVisibility(ope.getVisibility().toString());
					met.setStatic(ope.isStatic());
					met.setAbstract(ope.isAbstract());
					met.setType(ope.getType());
					met.setName(ope.getName());
					
					java.util.List params = ope.getParams();
					for(int j=0;j<params.size();j++){
						Argument arg = (Argument)params.get(j);
						ParameterDescriptor p = new ParameterDescriptor(arg.getName(), arg.getType());
						met.getArguments().add(p);
					}
				}
			}
		}
		
	}

	public void loadInterface(InterfaceModel model, InterfaceDescriptor jormodel) {
		List conns = model.getModelSourceConnections();
		for(int i=0; i<conns.size(); i++){
			Object conn = conns.get(i);
			if(conn instanceof GeneralizationModel){
				jormodel.setSubclass(true);
				AbstractUMLEntityModel target = ((GeneralizationModel)conn).getTarget();
				jormodel.getSuperInterfaces().add(configurations.getListaClasses().findInterface(getModelName(target)));
			}  else {
					if(conn instanceof AssociationModel) {
						importAssociation((AssociationModel) conn, jormodel);
					}
			}
		}
		importChildren(model, jormodel);
	} 

	
	
	private String getModelName(AbstractUMLEntityModel model){
		if(model instanceof ClassModel){
			return ((ClassModel)model).getName();
		}
		if(model instanceof InterfaceModel){
			return ((InterfaceModel)model).getName();
		}
		return null;
	}
	
	private void loadComponentList() {
		componentTableModel.limparTabela();
		Architeture architeture = configurations.getArchiteture();
		if (architeture.getComponents() != null) {
			for(Component v: architeture.getComponents()){
				componentTableModel.adicionarArquivo(v.getName());
			}
		}
		listComponents.updateUI();
	}
	
	public void loadFileList() {
		List<String> arquivosSelecionados = fileTableModel.getFileList();
		fileTableModel.cleanTable();
		List<String> componentes = componentTableModel.getListaComponentes();
		List<String> arquivos = getJavaOnRoad().criarListaArquivos(componentes);
		for(String s : arquivos) {
			boolean selected = arquivosSelecionados.contains(s);
			fileTableModel.adicionarArquivo(s, selected);
		}
	}
	
	private JTable getComponentList () {
		if(listComponents == null) {
			componentTableModel = new ComponentTableModel();
			listComponents = new JTable(componentTableModel);
			TableColumn column = null;
			int columnWidth[] = {50, 750};
			for (int i = 0; i < columnWidth.length; i++) {
				column = listComponents.getColumnModel().getColumn(i);
				column.setPreferredWidth(columnWidth[i]);
			}			
			updateFileListEvent = new TableModelListener(){  
				public void tableChanged(TableModelEvent tme) {  
					loadFileList();
				}  
			};  
			componentTableModel.addTableModelListener(updateFileListEvent);
		}
		return listComponents;
	}
	
	private JTable getFileList() {
		if(listFiles == null) {
			fileTableModel = new FileTableModel();
			listFiles = new JTable(fileTableModel);
			TableColumn column = null;
			int columnWidth[] = {50, 750};
			for (int i = 0; i < columnWidth.length; i++) {
			    column = listFiles.getColumnModel().getColumn(i);
		        column.setPreferredWidth(columnWidth[i]);
			}	
		}
		return listFiles;
	}

}
